package com.mirror.tk.codegenerator.ui.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Vector;

import javax.swing.table.AbstractTableModel;

public class JDBCAdapter extends AbstractTableModel {
	
	private static final long serialVersionUID = 1L;
	private Connection connection;
	private Statement statement;
	private ResultSet resultSet;
	private String[] columnNames = {};
	private Vector rows = new Vector();
	private ResultSetMetaData metaData;
	private String[] titles;
	private Object[] values;

	public JDBCAdapter(String url, String driverName, String user, String passwd) {
		try {
			Class.forName(driverName);
			System.out.println("Opening db connection");
			connection = DriverManager.getConnection(url, user, passwd);
			statement = connection.createStatement();
		} catch (ClassNotFoundException ex) {
			System.err.println("Cannot find the database driver classes.");
			System.err.println(ex);
		} catch (SQLException ex) {
			System.err.println("Cannot connect to this database.");
			System.err.println(ex);
		}
	}

	public JDBCAdapter(String url, String driverName, String user, String passwd, String[] titles, Object[] values) {
		this(url, driverName, user, passwd);
		this.titles = titles;
		this.values = values;
	}

	public JDBCAdapter(String[] titles, Object[] values) {
		this.titles = titles;
		this.values = values;
	}

	public void executeQuery(String[] titles, Object[] values, Connection connection, Statement statement, String query) {
		this.titles = titles;
		this.values = values;
		this.connection = connection;
		this.statement = statement;
		executeQuery(query);
	}

	public void executeQuery(Connection connection, Statement statement, String query) {
		this.connection = connection;
		this.statement = statement;
		executeQuery(query);
	}

	public void executeQuery(String query) {
		if (connection == null || statement == null) {
			System.err.println("There is no database to execute the query.");
			return;
		}
		try {
			resultSet = statement.executeQuery(query);
			metaData = resultSet.getMetaData();

			int numberOfColumns = metaData.getColumnCount();
			columnNames = new String[numberOfColumns + titles.length];
			// Get the column names and cache them.
			// Then we can close the connection.
			for (int column = 0; column < numberOfColumns; column++) {
				columnNames[column] = metaData.getColumnLabel(column + 1);
			}
			for (int column = numberOfColumns; column < numberOfColumns + titles.length; column++) {
				columnNames[column] = titles[column - numberOfColumns];
			}

			// Get all rows.
			rows = new Vector();
			while (resultSet.next()) {
				Vector newRow = new Vector();
				for (int i = 1; i <= numberOfColumns; i++) {
					newRow.addElement(resultSet.getObject(i));
				}
				for (int j = 0; j < values.length; j++)
					newRow.addElement(values[j]);
				rows.addElement(newRow);
			}
			// close(); Need to copy the metaData, bug in jdbc:odbc driver.
			fireTableChanged(null); // Tell the listeners a new table has
									// arrived.
		} catch (SQLException ex) {
			ex.printStackTrace();
			System.err.println(ex);
		}
	}

	public void close() throws SQLException {
		System.out.println("Closing db connection");
		resultSet.close();
		statement.close();
		connection.close();
	}

	public Vector getRows() {
		return rows;
	}

	protected void finalize() throws Throwable {
		close();
		super.finalize();
	}

	// ////////////////////////////////////////////////////////////////////////
	//
	// Implementation of the TableModel Interface
	//
	// ////////////////////////////////////////////////////////////////////////

	// MetaData

	public String getColumnName(int column) {
		if (columnNames[column] != null) {
			return columnNames[column];
		} else {
			return "";
		}
	}

	public Class getColumnClass(int column) {
		Vector row = (Vector) rows.elementAt(0);
		if (row.elementAt(column) == null) {
			return Object.class;
		}
		return row.elementAt(column).getClass();

		/*
		 * int type; try { type = metaData.getColumnType(column+1); } catch
		 * (SQLException e) { return super.getColumnClass(column); }
		 * 
		 * switch(type) { case Types.CHAR: case Types.VARCHAR: case
		 * Types.LONGVARCHAR: return String.class;
		 * 
		 * case Types.BIT: return Boolean.class;
		 * 
		 * case Types.TINYINT: case Types.SMALLINT: case Types.INTEGER: return
		 * Integer.class;
		 * 
		 * case Types.BIGINT: return Long.class;
		 * 
		 * case Types.FLOAT: case Types.DOUBLE: return Double.class;
		 * 
		 * case Types.DATE: return Date.class;
		 * 
		 * default: return Object.class; }
		 */
	}

	public boolean isCellEditable(int row, int column) {
		/*
		 * try { return metaData.isWritable(column+1); } catch (SQLException e)
		 * { return false; }
		 */
		return column >= getColumnCount() - titles.length;
	}

	public int getColumnCount() {
		return columnNames.length;
	}

	// Data methods

	public int getRowCount() {
		return rows.size();
	}

	public Object getValueAt(int aRow, int aColumn) {
		Vector row = (Vector) rows.elementAt(aRow);
		return row.elementAt(aColumn);
	}

	public String dbRepresentation(int column, Object value) {
		int type;

		if (value == null) {
			return "null";
		}

		try {
			type = metaData.getColumnType(column + 1);
		} catch (SQLException e) {
			return value.toString();
		}

		switch (type) {
		case Types.INTEGER:
		case Types.DOUBLE:
		case Types.FLOAT:
			return value.toString();
		case Types.BIT:
			return ((Boolean) value).booleanValue() ? "1" : "0";
		case Types.DATE:
			return value.toString(); // This will need some conversion.
		default:
			return "\"" + value.toString() + "\"";
		}

	}

	public void setValueAt(Object value, int row, int column) {
		/*
		 * try { String tableName = metaData.getTableName(column+1); // Some of
		 * the drivers seem buggy, tableName should not be null. if (tableName
		 * == null) { System.out.println("Table name returned null."); } String
		 * columnName = getColumnName(column); String query =
		 * "update "+tableName+
		 * " set "+columnName+" = "+dbRepresentation(column, value)+ " where ";
		 * // We don't have a model of the schema so we don't know the //
		 * primary keys or which columns to lock on. To demonstrate // that
		 * editing is possible, we'll just lock on everything. for(int col = 0;
		 * col<getColumnCount(); col++) { String colName = getColumnName(col);
		 * if (colName.equals("")) { continue; } if (col != 0) { query = query +
		 * " and "; } query = query + colName +" = "+ dbRepresentation(col,
		 * getValueAt(row, col)); } System.out.println(query);
		 * System.out.println("Not sending update to database"); //
		 * statement.executeQuery(query); } catch (SQLException e) { //
		 * e.printStackTrace(); System.err.println("Update failed"); }
		 */
		Vector dataRow = (Vector) rows.elementAt(row);
		dataRow.setElementAt(value, column);

	}
}
